﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.Messaging;
using System.Web;
using System.Net;
using System.IO;
using System.Reflection;
using log4net;

namespace APITwitter.Handlers
{
    public class TwitterConsumer : WebConsumer
    {
        #region Singleton

        private static readonly ServiceProviderDescription serviceDescription = new ServiceProviderDescription
        {
            RequestTokenEndpoint = new MessageReceivingEndpoint(Configuration.RequestTokenUrl, HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
            UserAuthorizationEndpoint = new MessageReceivingEndpoint(Configuration.UserAuthUrl, HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
            AccessTokenEndpoint = new MessageReceivingEndpoint(Configuration.AccessTokenUrl, HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
            TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
        };

        private static readonly IConsumerTokenManager tokenManager = SQLDBTokenManager.Current;

        private TwitterConsumer(ServiceProviderDescription sd, IConsumerTokenManager tm)
            : base(sd, tm)
        {
            log4net.Config.XmlConfigurator.Configure();
        }

        private static TwitterConsumer _Current = new TwitterConsumer(serviceDescription, tokenManager);

        public static TwitterConsumer Current
        {
            get { return _Current; }
        }
        #endregion

        #region API define
        public string GetResponseContent(HttpRequest req, string accessToken)
        {
            MessageReceivingEndpoint mre = generateMessageReceivingEndpoint(req);
            HttpWebResponse res;
            HttpWebRequest outGoingReq;

            Dictionary<string, string> postData = new Dictionary<string, string>();

            for (int i = 0; i < req.Form.Count; i++)
                postData.Add(req.Form.AllKeys[i], req.Form[i]);

            //this block is only for twitter official android client
            //it sucks to put update info in query that is not allowed by its own API
            if (!string.IsNullOrEmpty(req.QueryString["status"]))
            {
                string key;
                for (int i = 0; i < req.QueryString.Keys.Count; i++)
                {
                    key = req.QueryString.Keys[i];
                    postData.Remove(key);
                    postData.Add(key, req.QueryString[key]);
                }

                mre = new MessageReceivingEndpoint(mre.Location.AbsoluteUri.ToString().Replace(mre.Location.Query, string.Empty), HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest);
            }

            if (!string.IsNullOrEmpty(accessToken))
            {
                outGoingReq = this.PrepareAuthorizedRequest(mre, accessToken, postData);
                outGoingReq.ServicePoint.Expect100Continue = false;
            }
            else
            {
                outGoingReq = (HttpWebRequest)WebRequest.Create(mre.Location);
            }
            res = (HttpWebResponse)outGoingReq.GetResponse();

            StreamReader sr = new StreamReader(res.GetResponseStream());
            string s = sr.ReadToEnd();
            sr.Dispose();
            return s;

        }

        #endregion

        private MessageReceivingEndpoint generateMessageReceivingEndpoint(HttpRequest req)
        {
            string url = req.Url.AbsoluteUri.ToLower();
            if (url.EndsWith("&"))
                url = url.Substring(0, url.Length - 1);
            url = url.Replace(Configuration.DefaultBasePath.ToLower(), Configuration.DefaultAPIPrefix);

            return new MessageReceivingEndpoint(url,
                (req.HttpMethod == "POST" ? HttpDeliveryMethods.PostRequest : HttpDeliveryMethods.GetRequest) | HttpDeliveryMethods.AuthorizationHeaderRequest
                );
        }

    }
}
